// Unit test for the typelist

#include <iostream>
#include <cstdio>
#include <memory>
#include <cassert>
#include <string>
#include <typeinfo>
#include "fmbTL.h"
#include "fmbFn.h"

using namespace std;
using namespace fm::base;

typedef TL_0 TL0;
typedef TL_1(int) TLi;
typedef TL_2(int, double) TLid;
typedef TL_3(int, char, double) TLicd;

/// <summary>
///   The main function
/// </summary>
int main(int argc, char **argv){

  // length calculation test
  {
    assert(TLLength<TL0>::value == 0);
    assert(TLLength<TLi>::value == 1);
    assert(TLLength<TLid>::value == 2);
    assert(TLLength<TLicd>::value == 3);
    printf(" - length test done\n");
  }

  // invalid item access test, should produce a compile time error
  {
    //assert(typeid(TLAt<TL0, -1>::Type) == typeid(NullType));
    //assert(typeid(TLAt<TLi, -1>::Type) == typeid(NullType));
    //assert(typeid(TLAt<TLid, -1>::Type) == typeid(NullType));
    //assert(typeid(TLAt<TLicd, -1>::Type) == typeid(NullType));
    //assert(typeid(TLAt<TL0, 0>::Type) == typeid(NullType));
    //assert(typeid(TLAt<TLi, 1>::Type) == typeid(NullType));
    //assert(typeid(TLAt<TLid, 2>::Type) == typeid(NullType));
    //assert(typeid(TLAt<TLicd, 3>::Type) == typeid(NullType));
  }

  // valid element access
  {
    assert(typeid(TLAt<TLi, 0>::Type) == typeid(int));
    assert(typeid(TLAt<TLid, 0>::Type) == typeid(int));
    assert(typeid(TLAt<TLid, 1>::Type) == typeid(double));
    assert(typeid(TLAt<TLicd, 0>::Type) == typeid(int));
    assert(typeid(TLAt<TLicd, 1>::Type) == typeid(char));
    assert(typeid(TLAt<TLicd, 2>::Type) == typeid(double));

    printf(" - strict element access test done\n");
  }

  // non strict access test
  {
    assert(typeid(TLAtNonStrict<TL0, -1, EmptyType>::Type) == typeid(EmptyType));
    assert(typeid(TLAtNonStrict<TL0, 0, EmptyType>::Type) == typeid(EmptyType));
    assert(typeid(TLAtNonStrict<TLi, -1, EmptyType>::Type) == typeid(EmptyType));
    assert(typeid(TLAtNonStrict<TLi, 0, EmptyType>::Type) == typeid(int));
    assert(typeid(TLAtNonStrict<TLi, 1, EmptyType>::Type) == typeid(EmptyType));
    assert(typeid(TLAtNonStrict<TLid, -1, EmptyType>::Type) == typeid(EmptyType));
    assert(typeid(TLAtNonStrict<TLid, 0, EmptyType>::Type) == typeid(int));
    assert(typeid(TLAtNonStrict<TLid, 1, EmptyType>::Type) == typeid(double));
    assert(typeid(TLAtNonStrict<TLid, 2, EmptyType>::Type) == typeid(EmptyType));
    assert(typeid(TLAtNonStrict<TLicd, -1, EmptyType>::Type) == typeid(EmptyType));
    assert(typeid(TLAtNonStrict<TLicd, 0, EmptyType>::Type) == typeid(int));
    assert(typeid(TLAtNonStrict<TLicd, 1, EmptyType>::Type) == typeid(char));
    assert(typeid(TLAtNonStrict<TLicd, 2, EmptyType>::Type) == typeid(double));
    assert(typeid(TLAtNonStrict<TLicd, 3, EmptyType>::Type) == typeid(EmptyType));

    printf(" - non strict element access test done\n");
  }

  printf("\nThe whole test was successfull\n\n");
  return 0;
}
